﻿using System.Collections.Concurrent;
using System.ComponentModel;
using System.Reflection;
using System.Text;

namespace Dyao.Book.Core
{
    /// <summary>
    /// 枚举字符串附加格式化器
    /// </summary>
    public class EnumStringsDescriptionValueFormatter : IAdditionDataValueFormatter
    {
        private static ConcurrentDictionary<Type, List<KeyValuePair<string, string>>> _enumDescDict = new ConcurrentDictionary<Type, List<KeyValuePair<string, string>>>();
        private readonly Type _enumType;
        private readonly string _separator;
        private readonly string _descSeparator;
        private readonly StringComparison _stringComparison;

        /// <summary>
        /// 枚举字符串附加格式化器
        /// </summary>
        /// <param name="enumType">枚举类型</param>
        /// <param name="separator">字符分隔</param>
        /// <param name="descSeparator">显示字符分隔</param>
        /// <param name="isIgnoreCase">是否忽略大小写</param>
        public EnumStringsDescriptionValueFormatter(Type enumType, string separator = ",", string descSeparator = ",", bool isIgnoreCase = true)
        {
            this._enumType = enumType ?? throw new ArgumentNullException(nameof(enumType));
            this._separator = separator ?? throw new ArgumentNullException(nameof(separator));
            this._descSeparator = descSeparator ?? throw new ArgumentNullException(nameof(descSeparator));
            _stringComparison = isIgnoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.CurrentCulture;
        }

        public object Format(object value)
        {
            if (value == null) return string.Empty;
            var sourceStr = value.ToString();
            if (!string.IsNullOrWhiteSpace(sourceStr))
            {
                var arr = sourceStr.Split(_separator, StringSplitOptions.RemoveEmptyEntries);
                if (arr != null && arr.Length > 0)
                {
                    var sb = new StringBuilder();
                    var dict = GetEnumDescriptions(_enumType);
                    foreach (var item in arr)
                    {
                        var kv = dict.FirstOrDefault(a => string.Equals(a.Key, item, _stringComparison));
                        if (sb.Length > 0)
                        {
                            sb.Append(_descSeparator);
                        }

                        sb.Append(kv.Key != null ? kv.Value : item);
                    }

                    return sb.ToString();
                }
            }

            return sourceStr;
        }

        private static List<KeyValuePair<string, string>> GetEnumDescriptions(Type enumType)
        {
            return _enumDescDict.GetOrAdd(enumType, (t) =>
             {
                 var fis = t.GetFields(BindingFlags.Public | BindingFlags.NonPublic);

                 var list = new List<KeyValuePair<string, string>>();
                 foreach (var fi in fis)
                 {
                     string desc = null;
                     var attr = fi.GetCustomAttribute<DescriptionAttribute>(false);
                     if (attr != null)
                     {
                         desc = attr.Description;
                     }

                     if (string.IsNullOrWhiteSpace(desc))
                     {
                         desc = fi.Name;
                     }

                     list.Add(new KeyValuePair<string, string>(fi.Name, desc));
                 }

                 return list;
             });
        }
    }
}
